/*
 * Copyright 2014 by État de Genève (Switzerland)
 * All rights reserved.
 *
 * Author: ELCA Informatique SA
 */
define(['services/dataservice', 'durandal/app', 'q', 'plugins/router'],
    function (ds, app, Q, router) {

        /*{
         dossiers: {
         children: [],
         id: 'dossiers',
         mainCount: ...
         },
         ...
         }*/
        var menuModelCache = null;
        var _refreshEventName = 'cms:menu:refresh';
        var _topIdChangedEvent = 'cms:menu:topchanged';

        var menu = {
            refreshEventName: _refreshEventName,
            topIdChangedEvent: _topIdChangedEvent,

            // triggers the 'op:menu:refresh' event
            // if force update is activated, the event occurs once the menu is refreshed
            refreshCounters: refreshCounters,

            getSubMenu: getSubMenu,

            bindLeftMenu: bindLeftMenu,

            leftMenu: ko.observableArray()
        };

        return menu;

        /**
         * retrieves the menu and cache it
         */
        function refresh(currentMenu) {
            return ds.loadMenu(currentMenu)
                .then(function (m) {

                    // foreach topMenuItem,
                    // refresh all except children
                    if (!menuModelCache) {
                        menuModelCache = _.object(
                            _.map(m, function (topMenuItem) {
                                return [topMenuItem.id, topMenuItem];
                            })
                        );
                    } else {
                        _.each(m, function (topMenu) {
                            var newChildren = topMenu.children;
                            delete topMenu.children;

                            _.extend(menuModelCache[topMenu.id], topMenu);

                            if (newChildren && newChildren.length > 0) {
                                menuModelCache[topMenu.id].children = newChildren;
                            }
                        });
                    }
                });
        }

        /**
         * refresh the cache (if needed) and call the refresh event of the menu
         * returns the whole cache
         */
        function getSubMenu(currentMenuId, forceUpdate) {

            if (!menuModelCache || menuModelCache[currentMenuId].children.length === 0 || forceUpdate) {
                // get menu async, return promise
                return refresh(currentMenuId).then(function () {
                    app.trigger(_refreshEventName, menuModelCache);
                    return menuModelCache;
                });
            }

            return Q(menuModelCache);
        }

        function bindLeftMenu(type, topMenuId, topMenuHash, menuTree) {
            if (!menuTree || !menuTree[topMenuId]) {
                throw new Error(i18n.ts('cms:error.menuNotFound', topMenuId));
            }

            // if no type selected, select first one
            if (!type) {
                type = menuTree[topMenuId].children[0].id;
                router.navigate(router.activeInstruction().fragment + '/liste/' + type, false);
            }

            // recursively maps each menu item to a clickable link (with the correct href and isActive property
            function mapLinks(menuItems) {
                return _.map(menuItems, function (item) {

                    // builds link; e.g. #messages/liste/reqstandards
                    item.href = topMenuHash + '/liste/' + item.id;
                    item.isActive = item.id === type;
                    item.hasCounters = typeof item.mainCount !== 'undefined' && item.mainCount !== null;
                    item.children = item.children || [];

                    if (item.children && item.children.length > 0) {
                        item.children = mapLinks(item.children);
                    }

                    return item;
                });
            }

            this.leftMenu([]);
            this.leftMenu(mapLinks(menuTree[topMenuId].children));

            return type;
        }

        /**
         * refresh all menus, and call the refresh event
         */
        function refreshCounters(forceServerUpdate) {

            if (forceServerUpdate || !menuModelCache) {
                refresh().then(function () {
                    app.trigger(_refreshEventName, menuModelCache);
                });
            } else {
                app.trigger(_refreshEventName, menuModelCache);
            }
        }
    });